/* SPF (Sender Policy Framework) implementation.

Translation to C Copyright (c) 2007 Roberto Alsina <ralsina@kde.org>
Copyright (c) 2003, Terence Way
Portions Copyright (c) 2004,2005,2006 Stuart Gathman <stuart@bmsi.com>
Portions Copyright (c) 2005,2006 Scott Kitterman <scott@kitterman.com>
This module is free software, and you may redistribute it and/or modify
it under the same terms as Python itself, so long as this copyright message
and disclaimer are retained in their original form.

IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF
THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.

THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE.  THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS,
AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

For more information about SPF, a tool against email forgery, see
http://www.openspf.org/

For new versions check out http://code.google.com/p/raspf

*/

#include <stdlib.h>
#include <stdio.h>
#include <check.h>
#include "bstrlib/bstrlib.h"
#include "hash/hash.h"
#include "udns/udns.h"
#include "excc/exception-local.h"
#include "raspf.h"

START_TEST (test_parse_mechanism_1)
{
    bstring name=bfromcstr("");
    bstring domain=bfromcstr("");
    int cidr,cidr6;

    bstring s2=bfromcstr("a");
    bstring s3=bfromcstr("foo.com");
    parse_mechanism(s2,s3,
                    &name,&domain,&cidr,&cidr6);
    bstring s1=bformat("%s %s %d %d",
                       name->data,domain->data,cidr,cidr6);
    fail_unless (beqcstr(s1,"a foo.com -1 -1"));
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (s3);
    bdestroy (name);
    bdestroy (domain);

}
END_TEST

START_TEST (test_parse_mechanism_2)
{
    bstring name=bfromcstr("");
    bstring domain=bfromcstr("");
    int cidr,cidr6;

    bstring s2=bfromcstr("a:bar.com");
    bstring s3=bfromcstr("foo.com");
    parse_mechanism(s2,s3,
                    &name,&domain,&cidr,&cidr6);
    bstring s1=bformat("%s %s %d %d",
                       name->data,domain->data,cidr,cidr6);
    fail_unless (beqcstr(s1,"a bar.com -1 -1"));
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (s3);
    bdestroy (name);
    bdestroy (domain);
}
END_TEST

START_TEST (test_parse_mechanism_3)
{
    bstring name=bfromcstr("");
    bstring domain=bfromcstr("");
    int cidr,cidr6;

    bstring s2=bfromcstr("a/24");
    bstring s3=bfromcstr("foo.com");
    parse_mechanism(s2,s3,
                    &name,&domain,&cidr,&cidr6);
    bstring s1=bformat("%s %s %d %d",
                       name->data,domain->data,cidr,cidr6);
    fail_unless (beqcstr(s1,"a foo.com 24 -1"));
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (s3);
    bdestroy (name);
    bdestroy (domain);
}
END_TEST

START_TEST (test_parse_mechanism_4)
{
    bstring name=bfromcstr("");
    bstring domain=bfromcstr("");
    int cidr,cidr6;

    bstring s2=bfromcstr("A:foo:bar.com/16//48");
    bstring s3=bfromcstr("foo.com");
    parse_mechanism(s2,s3,
                    &name,&domain,&cidr,&cidr6);
    bstring s1=bformat("%s %s %d %d",
                       name->data,domain->data,cidr,cidr6);
    fail_unless (beqcstr(s1,"a foo:bar.com 16 48"));
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (s3);
    bdestroy (name);
    bdestroy (domain);
}
END_TEST

START_TEST (test_parse_mechanism_5)
{
    bstring name=bfromcstr("");
    bstring domain=bfromcstr("");
    int cidr,cidr6;

    bstring s2=bfromcstr("-exists:%{i}.%{s1}.100/86400.rate.%{d}");
    bstring s3=bfromcstr("foo.com");
    parse_mechanism(s2,s3,
                    &name,&domain,&cidr,&cidr6);
    bstring s1=bformat("%s %s %d %d",
                       name->data,domain->data,cidr,cidr6);
    fail_unless (beqcstr(s1,"-exists %{i}.%{s1}.100/86400.rate.%{d} -1 -1"));
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (s3);
    bdestroy (name);
    bdestroy (domain);
}
END_TEST

START_TEST (test_parse_mechanism_6)
{
    bstring name=bfromcstr("");
    bstring domain=bfromcstr("");
    int cidr,cidr6;

    bstring s2=bfromcstr("mx:%%%_/.Claranet.de/27");
    bstring s3=bfromcstr("foo.com");
    parse_mechanism(s2,s3,
                    &name,&domain,&cidr,&cidr6);
    bstring s1=bformat("%s %s %d %d",
                       name->data,domain->data,cidr,cidr6);
    fail_unless (beqcstr(s1,"mx %%%_/.Claranet.de 27 -1"));
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (s3);
    bdestroy (name);
    bdestroy (domain);
}
END_TEST

START_TEST (test_parse_mechanism_7)
{
    bstring name=bfromcstr("");
    bstring domain=bfromcstr("");
    int cidr,cidr6;

    bstring s2=bfromcstr("mx:%{d}//97");
    bstring s3=bfromcstr("foo.com");
    parse_mechanism(s2,s3,
                    &name,&domain,&cidr,&cidr6);
    bstring s1=bformat("%s %s %d %d",
                       name->data,domain->data,cidr,cidr6);
    fail_unless (beqcstr(s1,"mx %{d} -1 97"));
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (s3);
    bdestroy (name);
    bdestroy (domain);
}
END_TEST

START_TEST (test_parse_mechanism_8)
{
    bstring name=bfromcstr("");
    bstring domain=bfromcstr("");
    int cidr,cidr6;

    bstring s2=bfromcstr("iP4:192.0.0.0/8");
    bstring s3=bfromcstr("foo.com");
    parse_mechanism(s2,s3,
                    &name,&domain,&cidr,&cidr6);
    bstring s1=bformat("%s %s %d %d",
                       name->data,domain->data,cidr,cidr6);
    fail_unless (beqcstr(s1,"ip4 192.0.0.0 8 -1"));
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (s3);
    bdestroy (name);
    bdestroy (domain);
}
END_TEST

START_TEST (test_parse_mechanism_9)
{
    bstring name=bfromcstr("");
    bstring domain=bfromcstr("");
    int cidr,cidr6;

    bstring s2=bfromcstr("ip4:192.0.2.128/25");
    bstring s3=bfromcstr("foo.com");
    parse_mechanism(s2,s3,
                    &name,&domain,&cidr,&cidr6);
    bstring s1=bformat("%s %s %d %d",
                       name->data,domain->data,cidr,cidr6);
    fail_unless (beqcstr(s1,"ip4 192.0.2.128 25 -1"));
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (s3);
    bdestroy (name);
    bdestroy (domain);
}
END_TEST

START_TEST (test_parse_mechanism_10)
{
    bstring name=bfromcstr("");
    bstring domain=bfromcstr("");
    int cidr,cidr6;

    bstring s2=bfromcstr("exists");
    bstring s3=bfromcstr("foo.com");
    parse_mechanism(s2,s3,
                    &name,&domain,&cidr,&cidr6);
    bstring s1=bformat("%s %d %d",
                       name->data,cidr,cidr6);
    fail_unless (beqcstr(s1,"exists -1 -1") && domain==0);
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (s3);
    bdestroy (name);
    bdestroy (domain);
}
END_TEST

START_TEST (test_re_split2_1)
{
    bstring s=re_split2("r",RE_ARGS,'|');
    fail_unless (beqcstr(s,"||r||"));
    bdestroy (s);
}
END_TEST

START_TEST (test_re_split2_2)
{
    bstring s=re_split2("2r",RE_ARGS,'|');
    fail_unless (beqcstr(s,"|2|r||"));
    bdestroy (s);
}
END_TEST

START_TEST (test_re_split2_3)
{
    bstring s=re_split2("2",RE_ARGS,'|');
    fail_unless (beqcstr(s,"|2|||"));
    bdestroy (s);
}
END_TEST
START_TEST (test_re_split2_4)
{
    bstring s=re_split2("1r-",RE_ARGS,'|');
    fail_unless (beqcstr(s,"|1|r|-|"));
    bdestroy (s);
}
END_TEST
START_TEST (test_re_split2_5)
{
    bstring s=re_split2("a/24",RE_CIDR,'|');
    fail_unless (beqcstr(s,"a/|24|"));
    bdestroy (s);
}
END_TEST
START_TEST (test_re_split2_6)
{
    bstring s=re_split2("1/3//12",RE_DUAL_CIDR,'|');
    fail_unless (beqcstr(s,"1/3//|12|"));
    bdestroy (s);
}
END_TEST
START_TEST (test_re_split2_7)
{
    bstring s=re_split2 ("1a2a3a4a5","(a)",'|');
    fail_unless (beqcstr(s,"1|a|2|a|3|a|4|a|5"));
    bdestroy (s);
}
END_TEST
START_TEST (test_re_split2_8)
{
    bstring s=re_split2 ("abc=abc.-def=tttt",RE_MODIFIER,'|');
    fail_unless (beqcstr(s,"|abc|=abc.-def=tttt"));
    bdestroy (s);
}
END_TEST

START_TEST (test_re_split2_9)
{
    // From test modifier-charset-good
    bstring s=re_split2 ("moo.cow-far_out=man:dog/cat",RE_MODIFIER,'|');
    fail_unless (beqcstr(s,"|moo.cow-far_out|=man:dog/cat"));
    bdestroy (s);
}
END_TEST

START_TEST (test_url_encode_1)
{
    bstring s1=url_encode("a % ");
    fail_unless (beqcstr(s1,"a%20%25%20"));
    bdestroy (s1);
}
END_TEST



START_TEST (test_re_findall_1)
{
    bstring s1=bfromcstr("|");
    struct bstrList *l=re_findall ("%{i}.%{s1}.100",
                                   "%(%|_|-|(\\{[^\\}]*\\}))");
    bstring r=bjoin(l,s1);
    fail_unless (beqcstr(r,"%{i}|%{s1}|"));
    bstrListDestroy(l);
    bdestroy(r);
    bdestroy (s1);
}
END_TEST

START_TEST (test_split_1)
{
    bstring s1=bfromcstr("192.168.0.45");
    bstring s2=bfromcstr(".");
    bstring s3=bfromcstr("|");

    struct bstrList *l=split(s1,s2,0);
    bstring r=bjoin(l,s3);
    bstrListDestroy(l);
    fail_unless (beqcstr(r,"192|.|168|.|0|.|45"));

    bdestroy (r);
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (s3);
}
END_TEST
START_TEST (test_split_2)
{
    bstring s1=bfromcstr("terry@wayforward.net");
    bstring s2=bfromcstr("@.");
    bstring s3=bfromcstr("|");
    bstring s4=bfromcstr("terry|@|wayforward|.|net");

    struct bstrList *l=split(s1,s2,0);
    bstring r=bjoin(l,s3);
    bstrListDestroy(l);
    fail_unless (1==biseq(r,s4));
    bdestroy (r);
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (s3);
    bdestroy (s4);
}
END_TEST
START_TEST (test_split_3)
{
    bstring s1=bfromcstr("terry@wayforward.net");
    bstring s2=bfromcstr("@.");
    bstring s3=bfromcstr(".");
    bstring s4=bfromcstr("|");
    bstring s5=bfromcstr("terry|.|wayforward|.|net");

    struct bstrList *l=split(s1,s2,s3);
    bstring r=bjoin(l,s4);
    bstrListDestroy(l);
    fail_unless (1==biseq(r,s5));
    bdestroy (r);
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (s3);
    bdestroy (s4);
    bdestroy (s5);
}
END_TEST




START_TEST (test_insert_libspf_local_policy_1)
{
    bstring s=bfromcstr("v=spf1 -all");
    bstring r=insert_libspf_local_policy(s,0);
    fail_unless(beqcstr(r,"v=spf1 -all"));
    bdestroy(r);
    bdestroy(s);
}
END_TEST
START_TEST (test_insert_libspf_local_policy_2)
{
    bstring s1=bfromcstr("v=spf1 -all");
    bstring s2=bfromcstr("mx");
    bstring r=insert_libspf_local_policy(s1,s2);
    fail_unless (beqcstr(r,"v=spf1 -all"));
    bdestroy(r);
    bdestroy(s1);
    bdestroy(s2);
}
END_TEST
START_TEST (test_insert_libspf_local_policy_3)
{
    bstring s1=bfromcstr("v=spf1");
    bstring s2=bfromcstr("a mx ptr");
    bstring r=insert_libspf_local_policy(s1,s2);
    fail_unless (beqcstr(r,"v=spf1 a mx ptr"));
    bdestroy(r);
    bdestroy(s1);
    bdestroy(s2);
}
END_TEST
START_TEST (test_insert_libspf_local_policy_4)
{
    bstring s1=bfromcstr("v=spf1 mx -all");
    bstring s2=bfromcstr("a ptr");
    bstring r=insert_libspf_local_policy(s1,s2);
    fail_unless (beqcstr(r,"v=spf1 mx a ptr -all"));
    bdestroy(r);
    bdestroy(s1);
    bdestroy(s2);
}
END_TEST
START_TEST (test_insert_libspf_local_policy_5)
{
    bstring s1=bfromcstr("v=spf1 mx -include:foo.co +all");
    bstring s2=bfromcstr("a ptr");
    bstring r=insert_libspf_local_policy(s1,s2);
    fail_unless (beqcstr(r,"v=spf1 mx a ptr -include:foo.co +all"));
    bdestroy(r);
    bdestroy(s1);
    bdestroy(s2);
}
END_TEST
START_TEST (test_insert_libspf_local_policy_6)
{
    bstring s1=bfromcstr("v=spf1 mx ?include:foo.co +all");
    bstring s2=bfromcstr("a ptr");
    bstring r=insert_libspf_local_policy(s1,s2);
    fail_unless (beqcstr(r,"v=spf1 mx a ptr ?include:foo.co +all"));
    bdestroy(r);
    bdestroy(s1);
    bdestroy(s2);
}
END_TEST
START_TEST (test_insert_libspf_local_policy_7)
{
    bstring s1=bfromcstr("v=spf1 ip4:1.2.3.4 -a:example.net -all");
    bstring s2=bfromcstr("ip4:192.0.2.3 a:example.org");
    bstring r=insert_libspf_local_policy(s1,s2);
    fail_unless (beqcstr(r,"v=spf1 ip4:1.2.3.4 ip4:192.0.2.3 a:example.org -a:example.net -all"));
    bdestroy(r);
    bdestroy(s1);
    bdestroy(s2);
}
END_TEST




START_TEST (test_re_ip4_1)
{
    fail_unless(match("192.0.2.3",RE_IP4));
    fail_unless(validate_ipv4("192.0.2.3"));

    fail_unless(match("1.2.3.4",RE_IP4));
    fail_unless(validate_ipv4("1.2.3.4"));

    fail_unless(match("5.18.140.253",RE_IP4));
    fail_unless(validate_ipv4("5.18.140.253"));

    fail_if(match("1.2.3",RE_IP4));
    fail_if(validate_ipv4("1.2.3"));

    fail_if(match("5.18.140.258",RE_IP4));
    fail_if(validate_ipv4("5.18.140.258"));

    fail_if(match("5.18.140.252.44",RE_IP4));
    fail_if(validate_ipv4("5.18.140.252.44"));

    //That's 14o not 140 :-)
    fail_if(match("5.18.14O.252",RE_IP4));
    fail_if(validate_ipv4("5.18.14O.252"));

}
END_TEST

START_TEST (test_query_validate_mechanism_1)
{
    mechanism mech;
    struct tagbstring s1=bsStatic("A");
    struct tagbstring s2=bsStatic("a");
    struct tagbstring s3=bsStatic("email.example.com");
    struct tagbstring s4=bsStatic("pass");
    spf_query *q;

    q=spf_query_init("192.0.2.3",
                     "strong-bad@email.example.com.",
                     "mx.example.org",
                     0,0,1);
    mech=spf_query_validate_mechanism(q,&s1);

    fail_unless (1==biseq(mech.mech,&s1));
    fail_unless (1==biseq(mech.m,&s2));
    fail_unless (1==biseq(mech.arg,&s3));
    fail_unless (mech.cidrlength==32);
    fail_unless (1==biseq(mech.result,&s4));

    destroy_mechanism (mech);
    spf_query_destroy(q);

}
END_TEST

START_TEST (test_query_validate_mechanism_2)
{
    mechanism mech;
    spf_query *q;
    q=spf_query_init("192.0.2.3",
                     "strong-bad@email.example.com.",
                     "mx.example.org",
                     0,0,1);
    bstring s=bfromcstr("?mx:%{d}/27");
    mech=spf_query_validate_mechanism(q,s);
    bdestroy(s);

    fail_unless (beqcstr(mech.mech,"?mx:%{d}/27"));
    fail_unless (beqcstr(mech.m,"mx"));
    fail_unless (beqcstr(mech.arg,"email.example.com"));
    fail_unless (mech.cidrlength==27);
    fail_unless (beqcstr(mech.result,"neutral"));
    destroy_mechanism (mech);
    spf_query_destroy(q);

}
END_TEST

START_TEST (test_query_validate_mechanism_3)
{
    mechanism mech;
    spf_query *q;
    bstring s;
    try
    {
        q=spf_query_init("192.0.2.3",
                         "strong-bad@email.example.com.",
                         "mx.example.org",
                         0,0,1);
        s=bfromcstr("ip4:1.2.3.4/247");
        mech=spf_query_validate_mechanism(q,s);
        // Should never reach here;
        fail();
        destroy_mechanism (mech);

    }
    except
    {
        on (PERM_ERROR)
        {
            fail_unless (beqcstr(EXCEPTION.param1,
                                 "Invalid IP4 CIDR length: ip4:1.2.3.4/247"));
            bdestroy (EXCEPTION.param1);
            bdestroy (s);
        }
    }
    spf_query_destroy(q);
}
END_TEST

START_TEST (test_query_validate_mechanism_4)
{
    mechanism mech;
    spf_query *q;
    bstring s;
    try
    {
        q=spf_query_init("192.0.2.3",
                         "strong-bad@email.example.com.",
                         "mx.example.org",
                         0,0,1);
        s=bfromcstr("ip4:1.2.3.4/33");
        mech=spf_query_validate_mechanism(q,s);
        // Should never reach here;
        fail();
        destroy_mechanism (mech);
    }
    except
    {
        on (PERM_ERROR)
        {
            fail_unless (beqcstr(EXCEPTION.param1,
                                 "Invalid IP4 CIDR length: ip4:1.2.3.4/33"));
            bdestroy (EXCEPTION.param1);
            bdestroy (s);
        }
    }
    spf_query_destroy(q);
}
END_TEST

START_TEST (test_query_validate_mechanism_5)
{
    mechanism mech;
    spf_query *q;
    bstring s;
    try
    {
        q=spf_query_init("192.0.2.3",
                         "strong-bad@email.example.com.",
                         "mx.example.org",
                         0,0,1);
        s=bfromcstr("a:example.com:8080");
        mech=spf_query_validate_mechanism(q,s);
        fail();
        destroy_mechanism (mech);
    }
    except
    {
        on (PERM_ERROR)
        {
            fail_unless (beqcstr(EXCEPTION.param1,
                                 "Invalid domain found (use FQDN): example.com:8080"));
            bdestroy (EXCEPTION.param1);
            bdestroy(s);
        }
    }
    spf_query_destroy(q);
}
END_TEST

START_TEST (test_query_validate_mechanism_6)
{
    mechanism mech;
    spf_query *q;
    bstring s;
    try
    {
        q=spf_query_init("192.0.2.3",
                         "strong-bad@email.example.com.",
                         "mx.example.org",
                         0,0,1);
        s=bfromcstr("ip4:1.2.03.4/24");
        mech=spf_query_validate_mechanism(q,s);
        // Should never reach here;
        fail();
        destroy_mechanism (mech);
    }
    except
    {
        on (PERM_ERROR)
        {
            fail_unless (beqcstr(EXCEPTION.param1,
                                 "Invalid IP4 address: ip4:1.2.03.4/24"));
            bdestroy (EXCEPTION.param1);
            bdestroy(s);
        }
    }
    spf_query_destroy(q);
}
END_TEST

START_TEST (test_query_validate_mechanism_7)
{
    mechanism mech;
    spf_query *q;
    bstring s;
    try
    {
        q=spf_query_init("192.0.2.3",
                         "strong-bad@email.example.com.",
                         "mx.example.org",
                         0,0,1);
        s=bfromcstr("ip4:1.2.03.4/24");
        mech=spf_query_validate_mechanism(q,s);
        // Should never reach here;
        fail();
        destroy_mechanism (mech);
    }
    except
    {
        on (PERM_ERROR)
        {

            fail_unless(beqcstr(EXCEPTION.param1,
                               "Invalid IP4 address: ip4:1.2.03.4/24"));
            bdestroy (EXCEPTION.param1);
            bdestroy(s);
        }
    }
    spf_query_destroy(q);
}
END_TEST

START_TEST (test_query_validate_mechanism_8)
{
    mechanism mech;
    spf_query *q;
    bstring s;
    try
    {
        q=spf_query_init("192.0.2.3",
                         "strong-bad@email.example.com.",
                         "mx.example.org",
                         0,0,1);
        s=bfromcstr("-all:3030");
        mech=spf_query_validate_mechanism(q,s);
        // Should never reach here;
        fail();
        destroy_mechanism (mech);
    }
    except
    {
        on (PERM_ERROR)
        {
            fail_unless (beqcstr(EXCEPTION.param1,
                                 "Invalid all mechanism format - only qualifier allowed with all: -all:3030"));
            bdestroy (EXCEPTION.param1);
            bdestroy(s);
        }
    }
    spf_query_destroy (q);
}
END_TEST

START_TEST (test_query_validate_mechanism_9)
{
    spf_query *q;
    q=spf_query_init("192.0.2.3",
                     "strong-bad@email.example.com.",
                     "mx.example.org",
                     0,0,1);
    bstring s=bfromcstr("-mx:%%%_/.Clara.de/27");
    mechanism mech=spf_query_validate_mechanism(q,s);

    fail_unless (beqcstr(mech.mech,"-mx:%%%_/.Clara.de/27"));
    fail_unless (beqcstr(mech.m,"mx"));
    fail_unless (beqcstr(mech.arg,"% /.Clara.de"));
    fail_unless (mech.cidrlength==27);
    fail_unless (beqcstr(mech.result,"fail"));
    destroy_mechanism (mech);
    spf_query_destroy (q);
    bdestroy(s);
}
END_TEST

START_TEST (test_query_validate_mechanism_10)
{
    spf_query *q;
    q=spf_query_init("192.0.2.3",
                     "strong-bad@email.example.com.",
                     "mx.example.org",
                     0,0,1);

    bstring s=bfromcstr("~exists:%{i}.%{s1}.100/86400.rate.%{d}");
    mechanism mech=spf_query_validate_mechanism(q,s);

    fail_unless (beqcstr(mech.mech,"~exists:%{i}.%{s1}.100/86400.rate.%{d}"));
    fail_unless (beqcstr(mech.m,"exists"));

    // Hey, PySPF fails this one too!
    fail_unless (beqcstr(mech.arg,
                         "192.0.2.3.com.100/86400.rate.email.example.com"),
                 "PySPF 2.0.2 fails this one too");
    fail_unless (mech.cidrlength==32);
    fail_unless (beqcstr(mech.result,"softfail"));
    destroy_mechanism (mech);
    spf_query_destroy (q);
    bdestroy(s);
}
END_TEST

START_TEST (test_query_validate_mechanism_11)
{
    mechanism mech;
    spf_query *q;
    q=spf_query_init("192.0.2.3",
                     "strong-bad@email.example.com.",
                     "mx.example.org",
                     0,0,1);
    bstring s=bfromcstr("a:mail.example.com.");
    mech=spf_query_validate_mechanism(q,s);

    fail_unless (beqcstr(mech.mech,"a:mail.example.com."));
    fail_unless (beqcstr(mech.m,"a"));
    fail_unless (beqcstr(mech.arg,"mail.example.com"));
    fail_unless (mech.cidrlength==32);
    fail_unless (beqcstr(mech.result,"pass"));
    destroy_mechanism (mech);
    spf_query_destroy (q);
    bdestroy(s);
}
END_TEST

START_TEST (test_query_validate_mechanism_12)
{
    mechanism mech;
    spf_query *q;
    bstring s;
    try
    {
        q=spf_query_init("192.0.2.3",
                         "strong-bad@email.example.com.",
                         "mx.example.org",
                         0,0,1);
        s=bfromcstr("a:mail.example.com,");
        mech=spf_query_validate_mechanism(q,s);
        // Should never reach here;
        fail("It doesn't throw the exception");
        destroy_mechanism (mech);
    }
    except
    {
        on (PERM_ERROR)
        {
            fail_unless (beqcstr(EXCEPTION.param1,
                                 "Do not separate mechanisms with commas: a:mail.example.com,"));
            bdestroy (EXCEPTION.param1);
            bdestroy(s);
        }
    }
    spf_query_destroy (q);
}
END_TEST

START_TEST (test_query_validate_mechanism_13)
{
    /* From SPF's suite.

    Test: modifier-charset-bad2
    Description:  '=' character immediately after the name and before any ":" or "/"
    Scenario:  Record evaluation

    */
    bstring s;
    mechanism mech;
    spf_query *q;
    try
    {
        q=spf_query_init("1.2.3.4",
                         "foo@t4.example.com",
                         "mail.example.com",
                         0,0,1);
        s=bfromcstr("moo.cow/far_out=man:dog/cat");
        mech=spf_query_validate_mechanism(q,s);
        // Should never reach here;
        fail();
        destroy_mechanism (mech);
    }
    except
    {
        on (PERM_ERROR)
        {
            fail_unless (beqcstr(EXCEPTION.param1,
                                 "Unknown mechanism found: moo.cow/far_out=man:dog/cat"));
            bdestroy (EXCEPTION.param1);
            bdestroy (s);
        }
    }
    spf_query_destroy (q);
}
END_TEST

START_TEST (test_query_validate_mechanism_14)
{
    /* From libspf2's suite.

    Divergence with PySPF 2.0.3

    */

#ifndef USE_DUMMY_DNS
    bstring s;
    mechanism mech;
    spf_query *q;
    q=spf_query_init("192.0.2.129",
                     "92.spf1-test.mailzone.com",
                     "92.spf1-test.mailzone.com",
                     0,0,1);
    s=bfromcstr("ip4:192.0.2.128/25");
    mech=spf_query_validate_mechanism(q,s);
    destroy_mechanism (mech);
    spf_query_destroy (q);
#endif
}
END_TEST


START_TEST (test_query_expand_1)
{
    spf_query *q;
    bstring s1=bfromcstr("%{d}");
    bstring s2=bfromcstr("email.example.com");

    q=spf_query_init("192.0.2.3",
                     "strong-bad@email.example.com",
                     "mx.example.org",
                     0,0,1);
    bdestroy(q->p);
    q->p=bfromcstr("mx.example.org");
    bdestroy(q->r);
    q->r=bfromcstr("example.net");

    bstring r=spf_query_expand(q,s1,1);
    fail_unless (biseq(r,s2));

    spf_query_destroy (q);
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (r);
}
END_TEST

START_TEST (test_query_expand_2)
{
    spf_query *q;
    q=spf_query_init("192.0.2.3",
                     "strong-bad@email.example.com",
                     "mx.example.org",
                     0,0,1);
    bdestroy(q->p);
    q->p=bfromcstr("mx.example.org");
    bdestroy(q->r);
    q->r=bfromcstr("example.net");

    bstring s1=bfromcstr("%{d4}");
    bstring s2=bfromcstr("email.example.com");
    bstring r=spf_query_expand(q,s1,1);
    fail_unless (biseq(r,s2));
    spf_query_destroy (q);
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (r);

}
END_TEST

START_TEST (test_query_expand_3)
{
    spf_query *q;
    q=spf_query_init("192.0.2.3",
                     "strong-bad@email.example.com",
                     "mx.example.org",
                     0,0,1);
    bdestroy(q->p);
    q->p=bfromcstr("mx.example.org");
    bdestroy(q->r);
    q->r=bfromcstr("example.net");

    bstring s1=bfromcstr("%{d3}");
    bstring s2=bfromcstr("email.example.com");
    bstring r=spf_query_expand(q,s1,1);
    fail_unless (biseq(r,s2));
    spf_query_destroy (q);
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (r);
}
END_TEST

START_TEST (test_query_expand_4)
{
    spf_query *q;
    q=spf_query_init("192.0.2.3",
                     "strong-bad@email.example.com",
                     "mx.example.org",
                     0,0,1);
    bdestroy(q->p);
    q->p=bfromcstr("mx.example.org");
    bdestroy(q->r);
    q->r=bfromcstr("example.net");

    bstring s1=bfromcstr("%{d2}");
    bstring s2=bfromcstr("example.com");
    bstring r=spf_query_expand(q,s1,1);
    fail_unless (biseq(r,s2));
    spf_query_destroy (q);
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (r);
}
END_TEST

START_TEST (test_query_expand_5)
{
    spf_query *q;
    q=spf_query_init("192.0.2.3",
                     "strong-bad@email.example.com",
                     "mx.example.org",
                     0,0,1);
    bdestroy(q->p);
    q->p=bfromcstr("mx.example.org");
    bdestroy(q->r);
    q->r=bfromcstr("example.net");

    bstring s1=bfromcstr("%{d1}");
    bstring s2=bfromcstr("com");
    bstring r=spf_query_expand(q,s1,1);
    fail_unless (biseq(r,s2));
    spf_query_destroy (q);
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (r);
}
END_TEST

START_TEST (test_query_expand_6)
{
    spf_query *q;
    q=spf_query_init("192.0.2.3",
                     "strong-bad@email.example.com",
                     "mx.example.org",
                     0,0,1);
    bdestroy(q->p);
    q->p=bfromcstr("mx.example.org");
    bdestroy(q->r);
    q->r=bfromcstr("example.net");

    bstring s1=bfromcstr("%{p}");
    bstring s2=bfromcstr("mx.example.org");
    bstring r=spf_query_expand(q,s1,1);
    fail_unless (biseq(r,s2));
    spf_query_destroy (q);
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (r);
}
END_TEST

START_TEST (test_query_expand_7)
{
    spf_query *q;
    q=spf_query_init("192.0.2.3",
                     "strong-bad@email.example.com",
                     "mx.example.org",
                     0,0,1);
    bdestroy(q->p);
    q->p=bfromcstr("mx.example.org");
    bdestroy(q->r);
    q->r=bfromcstr("example.net");

    bstring s1=bfromcstr("%{p2}");
    bstring s2=bfromcstr("example.org");
    bstring r=spf_query_expand(q,s1,1);
    fail_unless (biseq(r,s2));
    spf_query_destroy (q);
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (r);
}
END_TEST

START_TEST (test_query_expand_8)
{
    spf_query *q;
    q=spf_query_init("192.0.2.3",
                     "strong-bad@email.example.com",
                     "mx.example.org",
                     0,0,1);
    bdestroy(q->p);
    q->p=bfromcstr("mx.example.org");
    bdestroy(q->r);
    q->r=bfromcstr("example.net");

    bstring s1=bfromcstr("%{dr}");
    bstring s2=bfromcstr("com.example.email");
    bstring r=spf_query_expand(q,s1,1);
    fail_unless (biseq(r,s2));
    spf_query_destroy (q);
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (r);
}
END_TEST

START_TEST (test_query_expand_9)
{
    spf_query *q;
    q=spf_query_init("192.0.2.3",
                     "strong-bad@email.example.com",
                     "mx.example.org",
                     0,0,1);
    bdestroy(q->p);
    q->p=bfromcstr("mx.example.org");
    bdestroy(q->r);
    q->r=bfromcstr("example.net");

    bstring s1=bfromcstr("%{d2r}");
    bstring s2=bfromcstr("example.email");
    bstring r=spf_query_expand(q,s1,1);
    fail_unless (biseq(r,s2));
    spf_query_destroy (q);
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (r);
}
END_TEST

START_TEST (test_query_expand_10)
{
    spf_query *q;
    q=spf_query_init("192.0.2.3",
                     "strong-bad@email.example.com",
                     "mx.example.org",
                     0,0,1);
    bdestroy(q->p);
    q->p=bfromcstr("mx.example.org");
    bdestroy(q->r);
    q->r=bfromcstr("example.net");
    bstring s1=bfromcstr("%{l}");
    bstring s2=bfromcstr("strong-bad");
    bstring r=spf_query_expand(q,s1,1);
    fail_unless (biseq(r,s2));
    spf_query_destroy (q);
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (r);
}
END_TEST

START_TEST (test_query_expand_11)
{
    spf_query *q;
    q=spf_query_init("192.0.2.3",
                     "strong-bad@email.example.com",
                     "mx.example.org",
                     0,0,1);
    bdestroy(q->p);
    q->p=bfromcstr("mx.example.org");
    bdestroy(q->r);
    q->r=bfromcstr("example.net");

    bstring s1=bfromcstr("%{l-}");
    bstring s2=bfromcstr("strong.bad");
    bstring r=spf_query_expand(q,s1,1);
    fail_unless (biseq(r,s2));
    spf_query_destroy (q);
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (r);
}
END_TEST

START_TEST (test_query_expand_12)
{
    spf_query *q;
    q=spf_query_init("192.0.2.3",
                     "strong-bad@email.example.com",
                     "mx.example.org",
                     0,0,1);
    bdestroy(q->p);
    q->p=bfromcstr("mx.example.org");
    bdestroy(q->r);
    q->r=bfromcstr("example.net");

    bstring s1=bfromcstr("%{lr}");
    bstring s2=bfromcstr("strong-bad");
    bstring r=spf_query_expand(q,s1,1);
    fail_unless (biseq(r,s2));
    spf_query_destroy (q);
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (r);
}
END_TEST

START_TEST (test_query_expand_13)
{
    spf_query *q;
    q=spf_query_init("192.0.2.3",
                     "strong-bad@email.example.com",
                     "mx.example.org",
                     0,0,1);
    bdestroy(q->p);
    q->p=bfromcstr("mx.example.org");
    bdestroy(q->r);
    q->r=bfromcstr("example.net");

    bstring s1=bfromcstr("%{lr-}");
    bstring s2=bfromcstr("bad.strong");
    bstring r=spf_query_expand(q,s1,1);
    fail_unless (biseq(r,s2));
    spf_query_destroy (q);
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (r);
}
END_TEST

START_TEST (test_query_expand_14)
{
    spf_query *q;
    q=spf_query_init("192.0.2.3",
                     "strong-bad@email.example.com",
                     "mx.example.org",
                     0,0,1);
    bdestroy(q->p);
    q->p=bfromcstr("mx.example.org");
    bdestroy(q->r);
    q->r=bfromcstr("example.net");

    bstring s1=bfromcstr("%{l1r-}");
    bstring s2=bfromcstr("strong");
    bstring r=spf_query_expand(q,s1,1);
    fail_unless (biseq(r,s2));
    spf_query_destroy (q);
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (r);
}
END_TEST

START_TEST (test_query_expand_15)
{
    spf_query *q;
    q=spf_query_init("192.0.2.3",
                     "strong-bad@email.example.com",
                     "mx.example.org",
                     0,0,1);
    bdestroy(q->p);
    q->p=bfromcstr("mx.example.org");
    bdestroy(q->r);
    q->r=bfromcstr("example.net");

    bstring s1=bfromcstr("%{c}");
    bstring s2=bfromcstr("192.0.2.3");
    bstring r=spf_query_expand(q,s1,0);
    fail_unless (biseq(r,s2));
    spf_query_destroy (q);
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (r);

}
END_TEST

START_TEST (test_query_expand_16)
{
    spf_query *q;
    q=spf_query_init("192.0.2.3",
                     "strong-bad@email.example.com",
                     "mx.example.org",
                     0,0,1);
    bdestroy(q->p);
    q->p=bfromcstr("mx.example.org");
    bdestroy(q->r);
    q->r=bfromcstr("example.net");

    bstring s1=bfromcstr("%{r}");
    bstring s2=bfromcstr("example.net");
    bstring r=spf_query_expand(q,s1,0);
    fail_unless (biseq(r,s2));
    spf_query_destroy (q);
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (r);
}
END_TEST

START_TEST (test_query_expand_17)
{
    spf_query *q;
    q=spf_query_init("192.0.2.3",
                     "strong-bad@email.example.com",
                     "mx.example.org",
                     0,0,1);
    bdestroy(q->p);
    q->p=bfromcstr("mx.example.org");
    bdestroy(q->r);
    q->r=bfromcstr("example.net");

    bstring s1=bfromcstr("%{ir}.%{v}._spf.%{d2}");
    bstring s2=bfromcstr("3.2.0.192.in-addr._spf.example.com");
    bstring r=spf_query_expand(q,s1,1);
    fail_unless (biseq(r,s2));
    spf_query_destroy (q);
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (r);
}
END_TEST

START_TEST (test_query_expand_18)
{
    spf_query *q;
    q=spf_query_init("192.0.2.3",
                     "strong-bad@email.example.com",
                     "mx.example.org",
                     0,0,1);
    bdestroy(q->p);
    q->p=bfromcstr("mx.example.org");
    bdestroy(q->r);
    q->r=bfromcstr("example.net");

    bstring s1=bfromcstr("%{lr-}.lp._spf.%{d2}");
    bstring s2=bfromcstr("bad.strong.lp._spf.example.com");
    bstring r=spf_query_expand(q,s1,1);
    fail_unless (biseq(r,s2));
    spf_query_destroy (q);
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (r);
}
END_TEST

START_TEST (test_query_expand_19)
{
    spf_query *q;
    q=spf_query_init("192.0.2.3",
                     "strong-bad@email.example.com",
                     "mx.example.org",
                     0,0,1);
    bdestroy(q->p);
    q->p=bfromcstr("mx.example.org");
    bdestroy(q->r);
    q->r=bfromcstr("example.net");

    bstring s1=bfromcstr("%{lr-}.lp.%{ir}.%{v}._spf.%{d2}");
    bstring s2=bfromcstr("bad.strong.lp.3.2.0.192.in-addr._spf.example.com");
    bstring r=spf_query_expand(q,s1,1);
    fail_unless (biseq(r,s2));
    spf_query_destroy (q);
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (r);
}
END_TEST

START_TEST (test_query_expand_20)
{
    spf_query *q;
    q=spf_query_init("192.0.2.3",
                     "strong-bad@email.example.com",
                     "mx.example.org",
                     0,0,1);
    bdestroy(q->p);
    q->p=bfromcstr("mx.example.org");
    bdestroy(q->r);
    q->r=bfromcstr("example.net");

    bstring s1=bfromcstr("%{ir}.%{v}.%{l1r-}.lp._spf.%{d2}");
    bstring s2=bfromcstr("3.2.0.192.in-addr.strong.lp._spf.example.com");
    bstring r=spf_query_expand(q,s1,1);
    fail_unless (biseq(r,s2));
    spf_query_destroy (q);
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (r);
}
END_TEST

START_TEST (test_query_expand_21)
{
    spf_query *q;
    bstring s1=bfromcstr("%(ir).%{v}.%{l1r-}.lp._spf.%{d2}");
    try
    {
        q=spf_query_init("192.0.2.3",
                         "strong-bad@email.example.com",
                         "mx.example.org",
                         0,0,1);
        bdestroy(q->p);
        q->p=bfromcstr("mx.example.org");
        bdestroy(q->r);
        q->r=bfromcstr("example.net");

        bstring r=spf_query_expand(q,s1,1);
        // Shouldn't be reached
        fail("No exception thrown in test_query_expand_21");
        bdestroy(r);
    }
    except
    {
        on (PERM_ERROR)
        {
            fail_unless (beqcstr(EXCEPTION.param1,
                                  "invalid-macro-char: %(ir)"));
            bdestroy (EXCEPTION.param1);
        }
    }
    bdestroy(s1);
    spf_query_destroy (q);
}
END_TEST

START_TEST (test_query_expand_22)
{
    spf_query *q;
    q=spf_query_init("192.0.2.3",
                     "strong-bad@email.example.com",
                     "mx.example.org",
                     0,0,1);
    bdestroy(q->p);
    q->p=bfromcstr("mx.example.org");
    bdestroy(q->r);
    q->r=bfromcstr("example.net");

    bstring s1=bfromcstr("%{p2}.trusted-domains.example.net");
    bstring s2=bfromcstr("example.org.trusted-domains.example.net");
    bstring r=spf_query_expand(q,s1,1);
    fail_unless (biseq(r,s2));
    spf_query_destroy (q);
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (r);
}
END_TEST

START_TEST (test_query_expand_23)
{
    spf_query *q;
    q=spf_query_init("192.0.2.3",
                     "strong-bad@email.example.com",
                     "mx.example.org",
                     0,0,1);
    bdestroy(q->p);
    q->p=bfromcstr("mx.example.org");
    bdestroy(q->r);
    q->r=bfromcstr("example.net");

    bstring s1=bfromcstr("%{p2}.trusted-domains.example.net.");
    bstring s2=bfromcstr("example.org.trusted-domains.example.net");
    bstring r=spf_query_expand(q,s1,1);
    fail_unless (biseq(r,s2));
    spf_query_destroy (q);
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (r);
}
END_TEST

START_TEST (test_query_expand_24)
{
    spf_query *q;
    q=spf_query_init("192.0.2.3",
                     "@email.example.com",
                     "mx.example.org",
                     0,0,1);

    bstring s1=bfromcstr("%{l}");
    bstring s2=bfromcstr("postmaster");
    bstring r=spf_query_expand(q,s1,1);
    fail_unless (biseq(r,s2));
    spf_query_destroy (q);
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (r);
}
END_TEST

START_TEST (test_query_expand_25)
{
    spf_query *q;
    q=spf_query_init("192.0.2.3",
                     "@email.example.com",
                     "mx.example.org",
                     0,0,1);

    bstring s1=bfromcstr("%{v}.a");
    bstring s2=bfromcstr("in-addr.a");
    bstring r=spf_query_expand(q,s1,1);
    fail_unless (biseq(r,s2));
    spf_query_destroy (q);
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (r);
}
END_TEST

START_TEST (test_query_expand_26)
{
    spf_query *q;
    q=spf_query_init("192.0.2.3",
                     "strong-bad@email.example.com.",
                     "mx.example.org",
                     0,0,1);

    bstring s1=bfromcstr("%{s1}");
    bstring s2=bfromcstr("");
    bstring r=spf_query_expand(q,s1,1);
    fail_unless (biseq(r,s2));
    spf_query_destroy (q);
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (r);
}
END_TEST

START_TEST (test_query_init_1)
{
    spf_query *q;
    q=spf_query_init("192.0.2.3",
                     "@email.example.com",
                     "mx.example.org",
                     0,0,1);
    fail_unless (beqcstr(q->i,"192.0.2.3"));
    fail_unless (beqcstr(q->s,"@email.example.com"));
    fail_unless (beqcstr(q->l,"postmaster"));
    fail_unless (beqcstr(q->d,"email.example.com"));
    fail_unless (beqcstr(q->h,"mx.example.org"));
    fail_unless (beqcstr(q->v,"in-addr"));
    fail_unless (q->p==0);
    fail_unless (beqcstr(q->o,"email.example.com"));
    fail_unless (beqcstr(q->r,"unknown"));
    fail_unless (beqcstr(q->c,"192.0.2.3"));
    fail_unless (beqcstr(q->A,"A"));
    fail_unless (q->cidrmax,32);
    fail_unless (beqcstr(q->ident,"mailfrom"));
    fail_unless (q->lookups==0);
    fail_unless (beqcstr(q->libspf_local,0));
    fail_unless (q->strict);
    spf_query_destroy (q);
}
END_TEST

START_TEST (test_split_email_1)
{
    bstring l,d,s1,s2;

    l=0;
    d=0;
    s1=bfromcstr("postmaster");
    s2=bfromcstr("wayforward.net");
    split_email("",
                "wayforward.net",&l,&d);
    fail_unless (1==biseq(l,s1));
    fail_unless (1==biseq(d,s2));
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (l);
    bdestroy (d);

    l=0;
    d=0;
    s1=bfromcstr("postmaster");
    s2=bfromcstr("foo.com");
    split_email("foo.com",
                "wayforward.net",&l,&d);
    fail_unless (1==biseq(l,s1));
    fail_unless (1==biseq(d,s2));
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (l);
    bdestroy (d);

    l=0;
    d=0;
    s1=bfromcstr("terry");
    s2=bfromcstr("wayforward.net");
    split_email("terry@wayforward.net",
                "optsw.com",&l,&d);
    fail_unless (1==biseq(l,s1));
    fail_unless (1==biseq(d,s2));
    bdestroy (s1);
    bdestroy (s2);
    bdestroy (l);
    bdestroy (d);

}
END_TEST

START_TEST (test_cidrmatch_1)
{
    spf_query *q;
    struct bstrList *l;
    bstring s;

    {
        spf_query *q;
        q=spf_query_init("192.0.2.129",
                         "92.spf1-test.mailzone.com",
                         "92.spf1-test.mailzone.com",
                         0,0,1);
        bstring s=bfromcstr("192.0.2.128");
        fail_unless(spf_query_cidrmatch1(q,s,25));

        bdestroy(s);
        spf_query_destroy (q);

    }

    {
        q=spf_query_init("192.0.2.3",
                         "strong-bad@email.example.com",
                         "mx.example.org",
                         0,0,1);

        s=bfromcstr("192.0.2.1|192.0.1.3");
        l=bsplit(s,'|');
        fail_if(spf_query_cidrmatch(q,l,32));
        fail_unless(spf_query_cidrmatch(q,l,24));
        bstrListDestroy(l);
        bdestroy(s);

        spf_query_destroy (q);
    }

    {
        q=spf_query_init("2001:0db8:0000:0000:0000:0000:1428:57a0",
                         "strong-bad@email.example.com",
                         "mx.example.org",
                         0,0,1);

        s=bfromcstr("2001:0db8:0000:0000:0000:0000:1428:57ab");
        l=bsplit(s,'|');
        fail_unless(spf_query_cidrmatch(q,l,122));
        fail_if(spf_query_cidrmatch(q,l,126));
        bstrListDestroy(l);
        bdestroy(s);

        s=bfromcstr("2001:0db8:0000:0000:0000:0000:1428:57a0");
        l=bsplit(s,'|');
        fail_unless(spf_query_cidrmatch(q,l,128));
        fail_unless(spf_query_cidrmatch(q,l,12));
        bstrListDestroy(l);
        bdestroy(s);

        s=bfromcstr("2001:0db8::1428:57a0");
        l=bsplit(s,'|');
        fail_unless(spf_query_cidrmatch(q,l,128));
        fail_unless(spf_query_cidrmatch(q,l,12));
        bstrListDestroy(l);
        bdestroy(s);

        s=bfromcstr("2001:0db8::1428:57a1");
        l=bsplit(s,'|');
        fail_if(spf_query_cidrmatch(q,l,128));
        fail_unless(spf_query_cidrmatch(q,l,12));
        bstrListDestroy(l);
        bdestroy(s);

        s=bfromcstr("::1.1.1.1");
        l=bsplit(s,'|');
        fail_unless(spf_query_cidrmatch(q,l,0));
        bstrListDestroy(l);
        bdestroy(s);

        spf_query_destroy (q);
    }

}
END_TEST

START_TEST (test_domainmatch_1)
{
    struct bstrList *l;
    bstring s1,s2;

    {
        s1=bfromcstr("FOO.COM");
        s2=bfromcstr("foo.com");
        l=bsplit(s1,'|');
        fail_unless(domainmatch(l,s2));
        bstrListDestroy(l);
        bdestroy (s1);
        bdestroy (s2);
    }

    {
        s1=bfromcstr("moo.foo.com");
        s2=bfromcstr("FOO.COM");
        l=bsplit(s1,'|');
        fail_unless(domainmatch(l,s2));
        bstrListDestroy(l);
        bdestroy (s1);
        bdestroy (s2);
    }

    {
        s1=bfromcstr("moo.bar.com");
        s2=bfromcstr("foo.com");
        l=bsplit(s1,'|');
        fail_if(domainmatch(l,s2));
        bstrListDestroy(l);
        bdestroy (s1);
        bdestroy (s2);
    }

}
END_TEST

START_TEST (test_dns_99_1)
{
#if 0
    spf_query *q;
    q=spf_query_init("192.0.2.3",
                     "strong-bad@email.example.com",
                     "mx.example.org",
                     0,0,1);

    bstring r=bjoin(spf_query_dns_99(q,bfromcstr("bmsi.com")),bfromcstr("|"));
    fail_unless(1==biseq(r,bfromcstr("v=spf1 ip4:24.248.44.156 a mx -all")));
    spf_query_destroy (q);
#endif
}
END_TEST

START_TEST (validate_domain_spec_1)
{
    // Some valid domain-ends ( "." toplabel [ "." ] )
    fail_unless(validate_domain_spec(".org"));
    fail_unless(validate_domain_spec("www.kde.org"));
    fail_unless(validate_domain_spec("www.kde.org."));
    fail_unless(validate_domain_spec("example3.com"));

    // Some invalid domain-ends ( "." toplabel [ "." ] )
    fail_if(validate_domain_spec("org"));
    fail_if(validate_domain_spec("www.kde.org.:8000"));
    fail_if(validate_domain_spec("www.kde.org:8000"));

    // From the invalid-domain-long test
    fail_unless(validate_domain_spec("%{H}.bar"));

    // From the a-numeric test
    fail_if(validate_domain_spec("111.222.33.44"));
}
END_TEST

START_TEST (best_guess_1)
{
    spf_query *q=spf_query_init("1.2.3.4","","SUPERVISION1",0,"example.com",1);
    int sc;
    bstring explanation=bfromcstr("");
    bstring res=spf_query_best_guess(q,0,&sc,&explanation);
    fail_unless(beqcstr(res,"none"));
    bdestroy(res);
    bdestroy(explanation);
    spf_query_destroy(q);
}
END_TEST

Suite *
spf_suite (void)
{
    Suite *s = suite_create ("SPF");

    TCase *best_guess = tcase_create ("best_guess");
    tcase_add_test (best_guess, best_guess_1);
    suite_add_tcase (s, best_guess);

    TCase *validate_domain_spec = tcase_create ("validate_domain_spec");
    tcase_add_test (validate_domain_spec, validate_domain_spec_1);
    suite_add_tcase (s, validate_domain_spec);

    TCase *spf_dns_99 = tcase_create ("dns_99");
    tcase_add_test (spf_dns_99, test_dns_99_1);
    suite_add_tcase (s, spf_dns_99);

    TCase *spf_domainmatch = tcase_create ("domainmatch");
    tcase_add_test (spf_domainmatch, test_domainmatch_1);
    suite_add_tcase (s, spf_domainmatch);

    TCase *spf_cidrmatch = tcase_create ("cidrmatch");
    tcase_add_test (spf_cidrmatch, test_cidrmatch_1);
    suite_add_tcase (s, spf_cidrmatch);

    TCase *spf_split_email = tcase_create ("split_email");
    tcase_add_test (spf_split_email, test_split_email_1);
    suite_add_tcase (s, spf_split_email);

    TCase *spf_query_init = tcase_create ("query_init");
    tcase_add_test (spf_query_init, test_query_init_1);
    suite_add_tcase (s, spf_query_init);

    TCase *spf_query_expand = tcase_create ("query_expand");
    tcase_add_test (spf_query_expand, test_query_expand_1);
    tcase_add_test (spf_query_expand, test_query_expand_2);
    tcase_add_test (spf_query_expand, test_query_expand_3);
    tcase_add_test (spf_query_expand, test_query_expand_4);
    tcase_add_test (spf_query_expand, test_query_expand_5);
    tcase_add_test (spf_query_expand, test_query_expand_6);
    tcase_add_test (spf_query_expand, test_query_expand_7);
    tcase_add_test (spf_query_expand, test_query_expand_8);
    tcase_add_test (spf_query_expand, test_query_expand_9);
    tcase_add_test (spf_query_expand, test_query_expand_10);
    tcase_add_test (spf_query_expand, test_query_expand_11);
    tcase_add_test (spf_query_expand, test_query_expand_12);
    tcase_add_test (spf_query_expand, test_query_expand_13);
    tcase_add_test (spf_query_expand, test_query_expand_14);
    tcase_add_test (spf_query_expand, test_query_expand_15);
    tcase_add_test (spf_query_expand, test_query_expand_16);
    tcase_add_test (spf_query_expand, test_query_expand_17);
    tcase_add_test (spf_query_expand, test_query_expand_18);
    tcase_add_test (spf_query_expand, test_query_expand_19);
    tcase_add_test (spf_query_expand, test_query_expand_20);
    tcase_add_test (spf_query_expand, test_query_expand_21);
    tcase_add_test (spf_query_expand, test_query_expand_22);
    tcase_add_test (spf_query_expand, test_query_expand_23);
    tcase_add_test (spf_query_expand, test_query_expand_24);
    tcase_add_test (spf_query_expand, test_query_expand_25);
    tcase_add_test (spf_query_expand, test_query_expand_26);
    suite_add_tcase (s, spf_query_expand);

    TCase *spf_query_validate_mechanism = tcase_create ("query_validate_mechanism");
    tcase_add_test (spf_query_validate_mechanism,
                    test_query_validate_mechanism_1);
    tcase_add_test (spf_query_validate_mechanism,
                    test_query_validate_mechanism_2);
    tcase_add_test (spf_query_validate_mechanism,
                    test_query_validate_mechanism_3);
    tcase_add_test (spf_query_validate_mechanism,
                    test_query_validate_mechanism_4);
    tcase_add_test (spf_query_validate_mechanism,
                    test_query_validate_mechanism_5);
    tcase_add_test (spf_query_validate_mechanism,
                    test_query_validate_mechanism_6);
    tcase_add_test (spf_query_validate_mechanism,
                    test_query_validate_mechanism_7);
    tcase_add_test (spf_query_validate_mechanism,
                    test_query_validate_mechanism_8);
    tcase_add_test (spf_query_validate_mechanism,
                    test_query_validate_mechanism_9);
    tcase_add_test (spf_query_validate_mechanism,
                    test_query_validate_mechanism_10);
    tcase_add_test (spf_query_validate_mechanism,
                    test_query_validate_mechanism_11);
    tcase_add_test (spf_query_validate_mechanism,
                    test_query_validate_mechanism_12);
    tcase_add_test (spf_query_validate_mechanism,
                    test_query_validate_mechanism_13);
    tcase_add_test (spf_query_validate_mechanism,
                    test_query_validate_mechanism_14);
    suite_add_tcase (s, spf_query_validate_mechanism);

    TCase *spf_re_ip4 = tcase_create ("re_ip4");
    tcase_add_test (spf_re_ip4, test_re_ip4_1);
    suite_add_tcase (s, spf_re_ip4);

    TCase *spf_parse_mechanism = tcase_create ("parse_mechanism");
    tcase_add_test (spf_parse_mechanism, test_parse_mechanism_1);
    tcase_add_test (spf_parse_mechanism, test_parse_mechanism_2);
    tcase_add_test (spf_parse_mechanism, test_parse_mechanism_3);
    tcase_add_test (spf_parse_mechanism, test_parse_mechanism_4);
    tcase_add_test (spf_parse_mechanism, test_parse_mechanism_5);
    tcase_add_test (spf_parse_mechanism, test_parse_mechanism_6);
    tcase_add_test (spf_parse_mechanism, test_parse_mechanism_7);
    tcase_add_test (spf_parse_mechanism, test_parse_mechanism_8);
    tcase_add_test (spf_parse_mechanism, test_parse_mechanism_9);
    tcase_add_test (spf_parse_mechanism, test_parse_mechanism_10);
    suite_add_tcase (s, spf_parse_mechanism);

    TCase *spf_re_split2 = tcase_create ("re_split2");
    tcase_add_test (spf_re_split2, test_re_split2_1);
    tcase_add_test (spf_re_split2, test_re_split2_2);
    tcase_add_test (spf_re_split2, test_re_split2_3);
    tcase_add_test (spf_re_split2, test_re_split2_4);
    tcase_add_test (spf_re_split2, test_re_split2_5);
    tcase_add_test (spf_re_split2, test_re_split2_6);
    tcase_add_test (spf_re_split2, test_re_split2_7);
    tcase_add_test (spf_re_split2, test_re_split2_8);
    tcase_add_test (spf_re_split2, test_re_split2_9);
    suite_add_tcase (s, spf_re_split2);

    TCase *spf_url_encode = tcase_create ("url_encode");
    tcase_add_test (spf_url_encode, test_url_encode_1);
    suite_add_tcase (s, spf_url_encode);

    TCase *spf_re_findall = tcase_create ("re_findall");
    tcase_add_test (spf_re_findall, test_re_findall_1);
    suite_add_tcase (s, spf_re_findall);

    TCase *spf_split = tcase_create ("split");
    tcase_add_test (spf_split, test_split_1);
    tcase_add_test (spf_split, test_split_2);
    tcase_add_test (spf_split, test_split_3);
    suite_add_tcase (s, spf_split);

    TCase *spf_insert_libspf_local_policy =
        tcase_create ("insert_libspf_local_policy");
    tcase_add_test (spf_insert_libspf_local_policy,
                    test_insert_libspf_local_policy_1);
    tcase_add_test (spf_insert_libspf_local_policy,
                    test_insert_libspf_local_policy_2);
    tcase_add_test (spf_insert_libspf_local_policy,
                    test_insert_libspf_local_policy_3);
    tcase_add_test (spf_insert_libspf_local_policy,
                    test_insert_libspf_local_policy_4);
    tcase_add_test (spf_insert_libspf_local_policy,
                    test_insert_libspf_local_policy_5);
    tcase_add_test (spf_insert_libspf_local_policy,
                    test_insert_libspf_local_policy_6);
    tcase_add_test (spf_insert_libspf_local_policy,
                    test_insert_libspf_local_policy_7);
    suite_add_tcase (s, spf_insert_libspf_local_policy);

    return s;

}


int
main (void)
{
    spf_init();
    int number_failed;
    Suite *s = spf_suite ();
    SRunner *sr = srunner_create (s);
    srunner_set_log (sr, "test.log");
    srunner_run_all (sr, CK_NORMAL);
    number_failed = srunner_ntests_failed (sr);
    srunner_free (sr);
    spf_close();
    return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}


